<?php
/*
Plugin Name: Secure invitation plugin for Wordpress MU
Description: Stops public signup on your Wordpress MU site, but allows users to email and invite their friend to join your blog community. This plugin is based on a plugin by kt (Gord), from http://www.ikazoku.com
Version: 1.0
Author: Chris Taylor
Author URI: http://www.stillbreathing.co.uk
Plugin URI: http://www.stillbreathing.co.uk/projects/mu-secure-invites/
Date: 2009-01-06
*/

// when the wp-signup.php page is requested
$secure_invite_signup_page = get_site_option("secure_invite_signup_page");
if ((strpos($_SERVER["REQUEST_URI"], "wp-signup.php") !== false || strpos($_SERVER["REQUEST_URI"], $secure_invite_signup_page)) && get_site_option("secure_invite_open_signup") != "1")
{
	// set the signup request as not valid
	$valid = false;

	// check the email address is a valid invitation
	if (isset($_SERVER["QUERY_STRING"]) && (secure_invites_is_valid_email($_SERVER["QUERY_STRING"]) || secure_invites_is_valid_email(trim(@$_POST["user_email"]))))
	{
		$valid = true;
		if ($_SERVER["QUERY_STRING"] != "")
		{
			$_POST['user_email'] = $_SERVER["QUERY_STRING"];
		}
	}

	// if the signup request is not valid
	if (!$valid)
	{
		// show the message
		$secure_invite_no_invite_message = get_site_option("secure_invite_no_invite_message");
		if ($secure_invite_no_invite_message == "") { $secure_invite_no_invite_message = "Sorry, you must be invited to join this community."; }
		// stop processing
		wp_die($secure_invite_no_invite_message);
		exit();
	}
}

// when the admin menu is built
add_action('admin_menu', 'secure_invites_add_admin');

// check an email address has been invited
function secure_invites_is_valid_email($email) {
	if ($email && is_email($email))
	{
		$timelimit = get_site_option("secure_invite_signup_time_limit");
		if ($timelimit == "")
		{
			// default time limit of 3 days
			$timelimit = 3;
		}
		global $wpdb;
		$sql = $wpdb->prepare("select count(id) from ".$wpdb->base_prefix."invitations where invited_email = '%s' and UNIX_TIMESTAMP(datestamp) > %d;", $email, (time()-($timelimit*60*60*24)));
		$invites = $wpdb->get_var($sql);
		
		if ($invites == "0")
		{
			return false;
		} else {
			return true;
		}
	} else {
		return false;
	}
}

// add the admin invitation button
function secure_invites_add_admin() {
	global $current_user, $wpdb;
	$registered = $wpdb->get_var($wpdb->prepare("select UNIX_TIMESTAMP(user_registered) from ".$wpdb->users." where id=%d;", $current_user->id));
	$secure_invite_days_after_joining = (int)get_site_option("secure_invite_days_after_joining");
	if ($secure_invite_days_after_joining == "") { $secure_invite_days_after_joining = 30; }
	if (is_site_admin())
	{
		add_submenu_page('index.php', 'Invite friends', 'Invite friends', 0, 'secure_invite', 'secure_invite_admin');
	}
	add_submenu_page('wpmu-admin.php', 'Invites', 'Invites', 10, 'secure_invite_list', 'secure_invite_list');
	add_submenu_page('wpmu-admin.php', 'Invite settings', 'Invite settings', 10, 'secure_invite_settings', 'secure_invite_settings');
}

// show the settings for secure invites
function secure_invite_settings()
{
	// check the invites table exists
	secure_invite_check_table();

	if (@$_POST && is_array($_POST) && count($_POST) > 0)
	{
		update_site_option("secure_invite_days_after_joining", (int)$_POST["secure_invite_days_after_joining"]);
		update_site_option("secure_invite_signup_page", $_POST["secure_invite_signup_page"]);
		update_site_option("secure_invite_no_invite_message", trim($_POST["secure_invite_no_invite_message"]));
		update_site_option("secure_invite_signup_time_limit", trim($_POST["secure_invite_signup_time_limit"]));
		update_site_option("secure_invite_default_message", trim($_POST["secure_invite_default_message"]));
		update_site_option("secure_invite_open_signup", trim($_POST["secure_invite_open_signup"]));
		
		echo '<div id="message" class="updated fade"><p><strong>'.__('The settings have been updated').'</strong></p></div>';
	}

	$secure_invite_days_after_joining = get_site_option("secure_invite_days_after_joining");
	if ($secure_invite_days_after_joining == "") { $secure_invite_days_after_joining = "30"; }
	
	$secure_invite_open_signup = get_site_option("secure_invite_open_signup");
	$open_signup = "";
	if ($secure_invite_open_signup == "1") { $open_signup = ' checked="checked"'; }
	
	$secure_invite_signup_page = get_site_option("secure_invite_signup_page");
	if ($secure_invite_signup_page == "") { $secure_invite_signup_page = "wp-signup.php"; }
	
	$secure_invite_no_invite_message = get_site_option("secure_invite_no_invite_message");
	if ($secure_invite_no_invite_message == "") { $secure_invite_no_invite_message = "Sorry, you must be invited to join this community."; }
	
	$secure_invite_signup_time_limit = get_site_option("secure_invite_signup_time_limit");
	if ($secure_invite_signup_time_limit == "") { $secure_invite_signup_time_limit = 3; }
	
	$secure_invite_default_message = get_site_option("secure_invite_default_message");
	if ($secure_invite_default_message == "") { $secure_invite_default_message = "
   	
To join and register, please visit [signuplink]

Regards,

[name]

Note: This invitation will work for the next [timeout] days. After that your invitation will expire and you will have to be invited again.
If clicking the URLs in this message does not work, copy and paste them into the address bar of your browser."; }

	echo '<div class="wrap">
	<h2>Invitation settings</h2>
	<p>Change the settings for secure invitations here.</p>
	<form action="wpmu-admin.php?page=secure_invite_settings" method="post">
	<fieldset>
	
	<p>A user must have been registered for how many days before they can invite friends?</p>
	<p><label for="secure_invite_days_after_joining" style="float:left;width:30%;">Inviting lockdown (days)</label>
	<input type="text" name="secure_invite_days_after_joining" id="secure_invite_days_after_joining" value="Only admin users can invite people" disabled="disabled" style="width:60%" /></p>
	
	<p>What is the address of the signup page? (wp-signup.php is the default)</p>
	<p><label for="secure_invite_signup_page" style="float:left;width:30%;">Signup page</label>
	<input type="text" name="secure_invite_signup_page" id="secure_invite_signup_page" value="'.$secure_invite_signup_page.'" style="width:60%" /></p>
	
	<p>What message do you want to show if someone tries to sign up without being invited?</p>
	<p><label for="secure_invite_no_invite_message" style="float:left;width:30%;">No invitation message</label>
	<input type="text" name="secure_invite_no_invite_message" id="secure_invite_no_invite_message" value="'.$secure_invite_no_invite_message.'" style="width:60%" /></p>
	
	<p>How many days would you like an invitation to be open for?</p>
	<p><label for="secure_invite_signup_time_limit" style="float:left;width:30%;">Time limit for signups (days)</label>
	<input type="text" name="secure_invite_signup_time_limit" id="secure_invite_signup_time_limit" value="'.$secure_invite_signup_time_limit.'" style="width:60%" /></p>
	
	<p>Allow anyone to sign up? This disables the security on the signup page</p>
	<p><label for="secure_invite_open_signup" style="float:left;width:30%;">Open signup</label>
	<input type="checkbox" name="secure_invite_open_signup" id="secure_invite_open_signup"' . $open_signup . ' value="1" /></p>
	
	<p>Enter the message you would like to appear below the users personal message in the invite email. There are four special keywords to enter which are automatically changed when the email is sent. Use these keywords:</p>
	<ul>
		<li><code>[sitename]</code> where you want the name of your site to appear</li>
		<li><code>[signuplink]</code> where you want the special link to the signup form to appear</li>
		<li><code>[name]</code> where you want the name of the email sender to appear</li>
		<li><code>[timeout]</code> where you want the number of days this invitation is valid to appear</li>
	</ul>
	<p><label for="secure_invite_default_message" style="float:left;width:30%;">Default message for invites</label>
	<textarea name="secure_invite_default_message" id="secure_invite_default_message" style="width:60%" rows="12" cols="30">'.$secure_invite_default_message.'</textarea></p>
	
	<p><button type="submit" name="secure_invite_save_settings" class="button">Save these settings</button></p>
	
	</fieldset>
	</form>
	';
	
	echo '</div>
	';
}

// add the list of invitations
function secure_invite_list()
{
	global $wpdb;
	
	echo '
	<div class="wrap">
	';

	// check the invites table exists
	secure_invite_check_table();
	
	// show the number of invites per month
	$sql = "select UNIX_TIMESTAMP(i.datestamp) as date,
			count(i.invited_email) as invites,
			(select count(i2.invited_email)
			from ".$wpdb->base_prefix."invitations i2
			inner join ".$wpdb->base_prefix."users u2 on u2.user_email = i2.invited_email
			where year(i2.datestamp) = year(i.datestamp)
			and month(i2.datestamp) = month(i.datestamp)) as signups
			from ".$wpdb->base_prefix."invitations i
			group by month(i.datestamp)
			order by i.datestamp desc
			limit 0, 12;";
	$invites_per_month = $wpdb->get_results($sql);
	$invites_per_month_num = count($invites_per_month);	
	echo '
	<div style="float:left;width:45%">
	<h2>Invitations per month</h2>
	';
	if ($invites_per_month && $invites_per_month_num > 0)
	{
	echo '
	<table summary="'.__("Invitations per month").'" class="widefat">
	<thead>
	<tr>
		<th>'.__("Month").'</th>
		<th>'.__("Invites sent").'</th>
		<th>'.__("Resulting signups").'</th>
	</tr>
	</thead>
	<tbody>
	';
	foreach ($invites_per_month as $invite_month)
	{
		if ($alt == '') { $alt = ' class="alternate"'; } else { $alt = ''; }
		echo '
		<tr'.$alt.'>
			<td>'.__(date("F Y", $invite_month->date)).'</td>
			<td>'.__($invite_month->invites).'</td>
			<td>'.__($invite_month->signups).'</td>
		</tr>
		';
	}
	echo '
	</tbody>
	</table>
	';
	} else {
	echo '
	<p>'.__("No invitations sent yet").'</p>
	';
	}
	echo '
	</div>
	';
	
	// get the best inviters
	$sql = "select u.user_nicename,
			count(i.invited_email) as invites,
			(select count(i2.invited_email)
			from ".$wpdb->base_prefix."invitations i2
			inner join ".$wpdb->base_prefix."users u2 on u2.user_email = i2.invited_email
			where i2.user_id = i.user_id) as signups
			from ".$wpdb->base_prefix."invitations i
			inner join ".$wpdb->base_prefix."users u on u.id = i.user_id
			group by i.user_id
			order by count(i.invited_email) desc
			limit 0, 12;";
	$best_inviters = $wpdb->get_results($sql);
	$best_inviters_num = count($best_inviters);	
	echo '
	<div style="float:right;width:45%">
	<h2>Best inviters</h2>
	';
	if ($best_inviters && $best_inviters_num > 0)
	{
	echo '
	<table summary="'.__("Best inviters").'" class="widefat">
	<thead>
	<tr>
		<th>'.__("Name").'</th>
		<th>'.__("Invites sent").'</th>
		<th>'.__("Resulting signups").'</th>
	</tr>
	</thead>
	<tbody>
	';
	foreach ($best_inviters as $best_inviter)
	{
		if ($alt == '') { $alt = ' class="alternate"'; } else { $alt = ''; }
		echo '
		<tr'.$alt.'>
			<td>'.__($best_inviter->user_nicename).'</td>
			<td>'.__($best_inviter->invites).'</td>
			<td>'.__($best_inviter->signups).'</td>
		</tr>
		';
	}
	echo '
	</tbody>
	</table>
	';
	} else {
	echo '
	<p>'.__("No invitations sent yet").'</p>
	';
	}
	echo '
	</div>
	';
			
	// get the page
	$page = @(int)$_GET["p"];
	if ($page == "")
	{
		$page = "1";
	}
	$start = ($page * 50) -50;
	if ($start == "") { $start = 0; }
	
	// get the invites
	$sql = $wpdb->prepare("select SQL_CALC_FOUND_ROWS i.user_id, i.invited_email, UNIX_TIMESTAMP(i.datestamp) as datestamp, u.user_nicename as inviter, l.user_nicename as signed_up
			from ".$wpdb->base_prefix."invitations i
			inner join ".$wpdb->users." u on u.id = i.user_id
			left outer join ".$wpdb->users." l on l.user_email = i.invited_email
			order by i.datestamp desc
			limit %d, 50", $start);
	$invites = $wpdb->get_results($sql);

	echo '
	<h2>Invitation list</h2>
	';
	
	$invites_num = count($invites);
	$total = $wpdb->get_var( "SELECT found_rows() AS found_rows" );
	$invites_pages = ceil($total/50);
	
	if ($invites && $invites_num > 0)
	{
		if ($invites_pages > 1)
		{
			$thisp = @$_GET["p"];
			if ($thisp == "") { $thisp = 1; }
			echo '<ul style="list-style: none;">
			';
			for ($i = 1; $i <= $invites_pages; $i++)
			{
				if ($i == $thisp)
				{
					echo '<li style="display: inline;">'.$i.'</li>
				';
				} else {
					echo '<li style="display: inline;"><a href="wpmu-admin.php?page=secure_invite_list&amp;p='.$i.'">'.$i.'</a></li>
				';
				}
			}
			echo '</ul>
			';
		}
		echo '<table summary="'.__("Invitations sent by site users").'" class="widefat">
		<thead>
		<tr>
			<th>'.__("Inviter").'</th>
			<th>'.__("Datestamp").'</th>
			<th>'.__("Invited email").'</th>
			<th>'.__("Signed up name").'</th>
		</tr>
		</thead>
		<tbody>
		';
		$alt = '';
		foreach ($invites as $invite)
		{
			if ($alt == '') { $alt = ' class="alternate"'; } else { $alt = ''; }
			echo '<tr'.$alt.'>
			<td>' . $invite->inviter . '</td>
			<td>' . date("F j, Y, g:i a", $invite->datestamp) . '</td>
			<td>' . $invite->invited_email . '</td>
			<td>' . $invite->signed_up . '</td>
			</tr>
			';
		}
		echo '
		</tbody>
		</table>
		';
		if ($invites_pages > 1)
		{
			echo '<ul style="list-style: none;">
			';
			for ($i = 1; $i <= $invites_pages; $i++)
			{
				if ($i == $thisp)
				{
					echo '<li style="display: inline;">'.$i.'</li>
				';
				} else {
					echo '<li style="display: inline;"><a href="wpmu-admin.php?page=secure_invite_list&amp;p='.$i.'">'.$i.'</a></li>
				';
				}
			}
			echo '</ul>
			';
		}
	} else {
		echo '<p>No invitations sent yet.</p>';
	}
	
	echo '</div>';
}

// check the invites table exists
function secure_invite_check_table()
{
	global $wpdb;
	// if the invitations table does not exist
	$sql = "select count(id) from ".$wpdb->base_prefix."invitations;";
	$exists = $wpdb->get_var($sql);
	if($exists == "")
	{
		require_once(ABSPATH . 'wp-admin/upgrade-functions.php');
		// include the file with the required database manipulation functions
		// create the table
		$sql = "create table ".$wpdb->base_prefix."invitations (
				id int  NOT NULL AUTO_INCREMENT,
				user_id int,
				invited_email varchar(255),
				datestamp datetime,
				PRIMARY KEY id (id),
				KEY user (user_id),
				KEY email (invited_email),
				KEY dtstamp (datestamp)
				) DEFAULT CHARACTER SET utf8;";
		dbDelta($sql);
	}
}

// add an invitation to the database
function secure_invite_admin() {
	global $current_site, $current_user, $blog_id, $wpdb;
	$site_url = $current_site->domain;
	
	// check the invites table exists
	secure_invite_check_table();

	if($_POST['action']=="send")
	{
		if(is_email($_POST['email']))
		{
			$usernickname = $current_user->display_name;
			$to = trim($_POST['email']);
			$from = $current_user->user_email;
			$pname = trim($_POST['name']);
			
			// save the invitation 
			$sql = $wpdb->prepare("insert into ".$wpdb->base_prefix."invitations
(user_id, invited_email, datestamp)
values
(%d, %s, now());", $current_user->id, $to);
									$wpdb->print_error();
			$query = $wpdb->query($sql);
			$query_error = mysql_error();
			// if the invitation could be saved
			if ($query)
			{
				if(!empty($pname)) {
					$subject = $pname.', '.$usernickname.'  has invited you to join '.$site_url;
					$message .= "Dear ".$pname.", ";
				}
				else {
					$subject = 'Hi there, '. $usernickname.'  has invited you to join '.$site_url;
					$message .= "Hi there, ";
				}
				
				$secure_invite_signup_time_limit = (int)get_site_option("secure_invite_signup_time_limit");
				if ($secure_invite_signup_time_limit == "") { $secure_invite_signup_time_limit = 3; }
				
				$secure_invite_signup_page = get_site_option("secure_invite_signup_page");
				if ($secure_invite_signup_page == "") { $secure_invite_signup_page = "wp-signup.php"; }
				
				$secure_invite_default_message = get_site_option("secure_invite_default_message");
				if ($secure_invite_default_message == "") { $secure_invite_default_message = "
	
To join and register, please visit [signuplink]

Regards,

[name]

Note: This invitation will work for the next [timeout] days. After that your invitation will expire and you will have to be invited again.
If clicking the URLs in this message does not work, copy and paste them into the address bar of your browser."; }

				$secure_invite_default_message = str_replace("[sitename]", $site_url, $secure_invite_default_message);
				$secure_invite_default_message = str_replace("[signuplink]", "http://" . $site_url . "/" . $secure_invite_signup_page . "?" . $to, $secure_invite_default_message);
				$secure_invite_default_message = str_replace("[name]", $usernickname, $secure_invite_default_message);
				$secure_invite_default_message = str_replace("[timeout]", $secure_invite_signup_time_limit, $secure_invite_default_message);
				
				$message = $message . "\n\n" . stripslashes($_POST['personalmessage']) . "\n\n" . $secure_invite_default_message;
				
				$headers = 'From: '. $from;
				

				wp_mail($to, $subject, $message, $headers);
				echo '<div id="message" class="updated fade"><p><strong>'.__('Your invitation has been successfully sent to').' '.$to.'.</strong></p></div>';
			// the invitation could not be saved, show an error
			} else {
			    $headers = 'From: '. $from;
			    wp_mail(get_site_option("admin_email"), "Secure invite failure for ".$from, "A user just tried to invite someone to join ".$site_url.". The following SQL query could not be completed:\n\n".$sql."\n\nThe error reported was:\n\n".$query_error."\n\nThis is an automatic email sent by the Secure Invites plugin.", $headers);
				echo '<div id="message" class="updated fade"><p><strong>'.__('Your invitation could not be sent to').' '.$to.'. '.__('Please try again. If it fails more than twice please contact the site administrator.').'</strong></p></div>';
			}
		}
		else
		{
			echo '<div id="message" class="updated fade"><p><strong>'.__('Please enter a valid Email Address').'</strong></p></div>';
		} // end error
	} // end if action is send
	
	echo '<div class="wrap">';
  echo '<h2>Invite a friend to join '.$site_url.'</h2> ';
  echo '<form name="form1" method="post" action="index.php?page=secure_invite"> 
    <input type="hidden" name="action" value="send" /> 
    <table width="100%" cellspacing="2" cellpadding="5" class="form-table"> 
      <tr valign="top"> 
        <th width="33%" scope="row">'.__('Name').':</th> 
        <td><input name="name" type="text" id="name" tabindex="1" value="" size="40" /></td> 
      </tr> 
      <tr valign="top"> 
        <th width="33%" scope="row">'.__('Email').':</th> 
        <td><input name="email" type="text" id="email" tabindex="2" value="" size="40" /><br />'.__('His/her email address, one at a time.').'</td> 
      </tr> ';
	echo '<tr valign="top">
        <th width="33%" scope="row">'.__('Personal Message').':</th> 
        <td><textarea rows="10" cols="50" name="personalmessage" tabindex="3" id="defaultmessage">';
  $message = sprintf(__("You have been invited to join the VU Multimedia Program Creative Community at %s. You can view and comment on all posts with only a username or you can create your own blog to make posts and contribute."), $site_url);
  echo $message;
	echo '</textarea></td> </tr>';
	echo '</table>'; 
  echo '<p class="submit"><input type="submit" name="Submit" tabindex="4" value="Send Invitation &raquo;" /></p>';
  echo '</form>';
	echo '</div>';
}
?>